#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <regex>
#include <sys/stat.h>


#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/InetAddress.h>
#include <muduo/net/TcpConnection.h>
#include <muduo/base/Logging.h>
#include <functional>
#include <memory>
#include "server.hpp"


namespace muduo{
    
#define DEFALT_TIMEOUT 10

    std::unordered_map<int, std::string> _statu_msg = {
        {100,  "Continue"},
        {101,  "Switching Protocol"},
        {102,  "Processing"},
        {103,  "Early Hints"},
        {200,  "OK"},
        {201,  "Created"},
        {202,  "Accepted"},
        {203,  "Non-Authoritative Information"},
        {204,  "No Content"},
        {205,  "Reset Content"},
        {206,  "Partial Content"},
        {207,  "Multi-Status"},
        {208,  "Already Reported"},
        {226,  "IM Used"},
        {300,  "Multiple Choice"},
        {301,  "Moved Permanently"},
        {302,  "Found"},
        {303,  "See Other"},
        {304,  "Not Modified"},
        {305,  "Use Proxy"},
        {306,  "unused"},
        {307,  "Temporary Redirect"},
        {308,  "Permanent Redirect"},
        {400,  "Bad Request"},
        {401,  "Unauthorized"},
        {402,  "Payment Required"},
        {403,  "Forbidden"},
        {404,  "Not Found"},
        {405,  "Method Not Allowed"},
        {406,  "Not Acceptable"},
        {407,  "Proxy Authentication Required"},
        {408,  "Request Timeout"},
        {409,  "Conflict"},
        {410,  "Gone"},
        {411,  "Length Required"},
        {412,  "Precondition Failed"},
        {413,  "Payload Too Large"},
        {414,  "URI Too Long"},
        {415,  "Unsupported Media Type"},
        {416,  "Range Not Satisfiable"},
        {417,  "Expectation Failed"},
        {418,  "I'm a teapot"},
        {421,  "Misdirected Request"},
        {422,  "Unprocessable Entity"},
        {423,  "Locked"},
        {424,  "Failed Dependency"},
        {425,  "Too Early"},
        {426,  "Upgrade Required"},
        {428,  "Precondition Required"},
        {429,  "Too Many Requests"},
        {431,  "Request Header Fields Too Large"},
        {451,  "Unavailable For Legal Reasons"},
        {501,  "Not Implemented"},
        {502,  "Bad Gateway"},
        {503,  "Service Unavailable"},
        {504,  "Gateway Timeout"},
        {505,  "HTTP Version Not Supported"},
        {506,  "Variant Also Negotiates"},
        {507,  "Insufficient Storage"},
        {508,  "Loop Detected"},
        {510,  "Not Extended"},
        {511,  "Network Authentication Required"}
    };

    std::unordered_map<std::string, std::string> _mime_msg = {
        {".aac",        "audio/aac"},
        {".abw",        "application/x-abiword"},
        {".arc",        "application/x-freearc"},
        {".avi",        "video/x-msvideo"},
        {".azw",        "application/vnd.amazon.ebook"},
        {".bin",        "application/octet-stream"},
        {".bmp",        "image/bmp"},
        {".bz",         "application/x-bzip"},
        {".bz2",        "application/x-bzip2"},
        {".csh",        "application/x-csh"},
        {".css",        "text/css"},
        {".csv",        "text/csv"},
        {".doc",        "application/msword"},
        {".docx",       "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
        {".eot",        "application/vnd.ms-fontobject"},
        {".epub",       "application/epub+zip"},
        {".gif",        "image/gif"},
        {".htm",        "text/html"},
        {".html",       "text/html"},
        {".ico",        "image/vnd.microsoft.icon"},
        {".ics",        "text/calendar"},
        {".jar",        "application/java-archive"},
        {".jpeg",       "image/jpeg"},
        {".jpg",        "image/jpeg"},
        {".js",         "text/javascript"},
        {".json",       "application/json"},
        {".jsonld",     "application/ld+json"},
        {".mid",        "audio/midi"},
        {".midi",       "audio/x-midi"},
        {".mjs",        "text/javascript"},
        {".mp3",        "audio/mpeg"},
        {".mpeg",       "video/mpeg"},
        {".mpkg",       "application/vnd.apple.installer+xml"},
        {".odp",        "application/vnd.oasis.opendocument.presentation"},
        {".ods",        "application/vnd.oasis.opendocument.spreadsheet"},
        {".odt",        "application/vnd.oasis.opendocument.text"},
        {".oga",        "audio/ogg"},
        {".ogv",        "video/ogg"},
        {".ogx",        "application/ogg"},
        {".otf",        "font/otf"},
        {".png",        "image/png"},
        {".pdf",        "application/pdf"},
        {".ppt",        "application/vnd.ms-powerpoint"},
        {".pptx",       "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
        {".rar",        "application/x-rar-compressed"},
        {".rtf",        "application/rtf"},
        {".sh",         "application/x-sh"},
        {".svg",        "image/svg+xml"},
        {".swf",        "application/x-shockwave-flash"},
        {".tar",        "application/x-tar"},
        {".tif",        "image/tiff"},
        {".tiff",       "image/tiff"},
        {".ttf",        "font/ttf"},
        {".txt",        "text/plain"},
        {".vsd",        "application/vnd.visio"},
        {".wav",        "audio/wav"},
        {".weba",       "audio/webm"},
        {".webm",       "video/webm"},
        {".webp",       "image/webp"},
        {".woff",       "font/woff"},
        {".woff2",      "font/woff2"},
        {".xhtml",      "application/xhtml+xml"},
        {".xls",        "application/vnd.ms-excel"},
        {".xlsx",       "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
        {".xml",        "application/xml"},
        {".xul",        "application/vnd.mozilla.xul+xml"},
        {".zip",        "application/zip"},
        {".3gp",        "video/3gpp"},
        {".3g2",        "video/3gpp2"},
        {".7z",         "application/x-7z-compressed"}
    };

    class Util {
        public:
            static std::string getLineAndPop(muduo::net::Buffer* buf) {
                const char* crlf = buf->findCRLF();
                if (!crlf) return "";
                
                size_t len = crlf - buf->peek() + 2;
                std::string line(buf->peek(), len);
                buf->retrieve(len); 
                return line;
                
            }
            static size_t Split(const std::string &src, const std::string &sep, std::vector<std::string> *arry) {
                size_t offset = 0;
            
                while(offset < src.size()) {
                    size_t pos = src.find(sep, offset);//在src字符串偏移量offset处，开始向后查找sep字符/字串，返回查找到的位置
                    if (pos == std::string::npos) {//没有找到特定的字符
                        
                        if(pos == src.size()) break;
                        arry->push_back(src.substr(offset));
                        return arry->size();
                    }
                    if (pos == offset) {
                        offset = pos + sep.size();
                        continue;//当前字串是一个空的，没有内容
                    }
                    arry->push_back(src.substr(offset, pos - offset));
                    offset = pos + sep.size();
                }
                return arry->size();
            }
            //读取文件的所有内容，将读取的内容放到一个Buffer中
            static bool ReadFile(const std::string &filename, std::string *buf) {
                std::ifstream ifs(filename, std::ios::binary);
                if (ifs.is_open() == false) {
                    printf("OPEN %s FILE FAILED!!", filename.c_str());
                    return false;
                }
                size_t fsize = 0;
                ifs.seekg(0, ifs.end);//跳转读写位置到末尾
                fsize = ifs.tellg();  //获取当前读写位置相对于起始位置的偏移量，从末尾偏移刚好就是文件大小
                ifs.seekg(0, ifs.beg);//跳转到起始位置
                buf->resize(fsize); //开辟文件大小的空间
                ifs.read(&(*buf)[0], fsize);
                if (ifs.good() == false) {
                    printf("READ %s FILE FAILED!!", filename.c_str());
                    ifs.close();
                    return false;
                }
                ifs.close();
                return true;
            }
            //向文件写入数据
            static bool WriteFile(const std::string &filename, const std::string &buf) {
                std::ofstream ofs(filename, std::ios::binary | std::ios::trunc);
                if (ofs.is_open() == false) {
                    printf("OPEN %s FILE FAILED!!", filename.c_str());
                    return false;
                }
                ofs.write(buf.c_str(), buf.size());
                if (ofs.good() == false) {
                    ERR_LOG("WRITE %s FILE FAILED!", filename.c_str());
                    ofs.close();    
                    return false;
                }
                ofs.close();
                return true;
            }
            //URL编码，避免URL中资源路径与查询字符串中的特殊字符与HTTP请求中特殊字符产生歧义
            //编码格式：将特殊字符的ascii值，转换为两个16进制字符，前缀%   C++ -> C%2B%2B
            //  不编码的特殊字符： RFC3986文档规定 . - _ ~ 字母，数字属于绝对不编码字符
            //RFC3986文档规定，编码格式 %HH 
            //W3C标准中规定，查询字符串中的空格，需要编码为+， 解码则是+转空格
            static std::string UrlEncode(const std::string url, bool convert_space_to_plus) {
                std::string res;
                for (auto &c : url) {
                    if (c == '.' || c == '-' || c == '_' || c == '~' || isalnum(c)) {
                        res += c;
                        continue;
                    }
                    if (c == ' ' && convert_space_to_plus == true) {
                        res += '+';
                        continue;
                    }
                    //剩下的字符都是需要编码成为 %HH 格式
                    char tmp[4] = {0};
                    //snprintf 与 printf比较类似，都是格式化字符串，只不过一个是打印，一个是放到一块空间中
                    snprintf(tmp, 4, "%%%02X", c);
                    res += tmp;
                }
                return res;
            }
            static char HEXTOI(char c) {
                if (c >= '0' && c <= '9') {
                    return c - '0';
                }else if (c >= 'a' && c <= 'z') {
                    return c - 'a' + 10;
                }else if (c >= 'A' && c <= 'Z') {
                    return c - 'A' + 10;
                }
                return -1; 
            }
            static std::string UrlDecode(const std::string url, bool convert_plus_to_space) {
                //遇到了%，则将紧随其后的2个字符，转换为数字，第一个数字左移4位，然后加上第二个数字  + -> 2b  %2b->2 << 4 + 11
                std::string res;
                for (int i = 0; i < url.size(); i++) {
                    if (url[i] == '+' && convert_plus_to_space == true) {
                        res += ' ';
                        continue;
                    }
                    if (url[i] == '%' && (i + 2) < url.size()) {
                        char v1 = HEXTOI(url[i + 1]);
                        char v2 = HEXTOI(url[i + 2]);
                        char v = v1 * 16 + v2;
                        res += v;
                        i += 2;
                        continue;
                    }
                    res += url[i];
                }
                return res;
            }
            //响应状态码的描述信息获取
            static std::string StatuDesc(int statu) {
                
                auto it = _statu_msg.find(statu);
                if (it != _statu_msg.end()) {
                    return it->second;
                }
                return "Unknow";
            }
            //根据文件后缀名获取文件mime
            static std::string ExtMime(const std::string &filename) {
                
                // a.b.txt  先获取文件扩展名
                size_t pos = filename.find_last_of('.');
                if (pos == std::string::npos) {
                    return "application/octet-stream";
                }
                //根据扩展名，获取mime
                std::string ext = filename.substr(pos);
                auto it = _mime_msg.find(ext);
                if (it == _mime_msg.end()) {
                    return "application/octet-stream";
                }
                return it->second;
            }
            //判断一个文件是否是一个目录
            static bool IsDirectory(const std::string &filename) {
                struct stat st;
                int ret = stat(filename.c_str(), &st);
                if (ret < 0) {
                    return false;
                }
                return S_ISDIR(st.st_mode);
            }
            //判断一个文件是否是一个普通文件
            static bool IsRegular(const std::string &filename) {
                struct stat st;
                int ret = stat(filename.c_str(), &st);
                if (ret < 0) {
                    return false;
                }
                return S_ISREG(st.st_mode);
            }
        
            static bool ValidPath(const std::string &path) {
                
                std::vector<std::string> subdir;
                Split(path, "/", &subdir);
                int level = 0;
                for (auto &dir : subdir) {
                    if (dir == "..") {
                        level--; 
                        if (level < 0) return false;
                        continue;
                    }
                    level++;
                }
                return true;
            }
    };

    class HttpRequest {
        public:
            std::string _method;      //请求方法
            std::string _path;        //资源路径
            std::string _version;     //协议版本
            std::string _body;        //请求正文
            std::smatch _matches;     //资源路径的正则提取数据
            std::unordered_map<std::string, std::string> _headers;  //头部字段
            std::unordered_map<std::string, std::string> _params;   //查询字符串
        public:
            HttpRequest():_version("HTTP/1.1") {}
            void ReSet() {
                _method.clear();
                _path.clear();
                _version = "HTTP/1.1";
                _body.clear();
                std::smatch match;
                _matches.swap(match);
                _headers.clear();
                _params.clear();
            }
            //插入头部字段
            void SetHeader(const std::string &key, const std::string &val) {
                _headers.insert(std::make_pair(key, val));
            }
            //判断是否存在指定头部字段
            bool HasHeader(const std::string &key) const {
                auto it = _headers.find(key);
                if (it == _headers.end()) {
                    return false;
                }
                return true;
            }
            //获取指定头部字段的值
            std::string GetHeader(const std::string &key) const {
                auto it = _headers.find(key);
                if (it == _headers.end()) {
                    return "";
                }
                return it->second;
            }
            //插入查询字符串
            void SetParam(const std::string &key, const std::string &val) {
                _params.insert(std::make_pair(key, val));
            }
            //判断是否有某个指定的查询字符串
            bool HasParam(const std::string &key) const {
                auto it = _params.find(key);
                if (it == _params.end()) {
                    return false;
                }
                return true;
            }
            //获取指定的查询字符串
            std::string GetParam(const std::string &key) const {
                auto it = _params.find(key);
                if (it == _params.end()) {
                    return "";
                }
                return it->second;
            }
            //获取正文长度
            size_t ContentLength() const {
                // Content-Length: 1234\r\n
                bool ret = HasHeader("Content-Length");
                if (ret == false) {
                    return 0;
                }
                std::string clen = GetHeader("Content-Length");
                return std::stol(clen);
            }
            //判断是否是短链接
            bool Close() const {
                // 没有Connection字段，或者有Connection但是值是close，则都是短链接，否则就是长连接
                if (HasHeader("Connection") == true && GetHeader("Connection") == "keep-alive") {
                    return false;
                }
                return true;
            }
    };

    class HttpResponse {
        public:
            int _statu;
            bool _redirect_flag;
            std::string _body;
            std::string _redirect_url;
            std::unordered_map<std::string, std::string> _headers;
        public:
            HttpResponse():_redirect_flag(false), _statu(200) {}
            HttpResponse(int statu):_redirect_flag(false), _statu(statu) {} 
            void ReSet() {
                _statu = 200;
                _redirect_flag = false;
                _body.clear();
                _redirect_url.clear();
                _headers.clear();
            }
            //插入头部字段
            void SetHeader(const std::string &key, const std::string &val) {
                _headers.insert(std::make_pair(key, val));
            }
            //判断是否存在指定头部字段
            bool HasHeader(const std::string &key) {
                auto it = _headers.find(key);
                if (it == _headers.end()) {
                    return false;
                }
                return true;
            }
            //获取指定头部字段的值
            std::string GetHeader(const std::string &key) {
                auto it = _headers.find(key);
                if (it == _headers.end()) {
                    return "";
                }
                return it->second;
            }
            void SetContent(const std::string &body,  const std::string &type = "text/html") {
                _body = body;
                SetHeader("Content-Type", type);
            }
            void SetRedirect(const std::string &url, int statu = 302) {
                _statu = statu;
                _redirect_flag = true;
                _redirect_url = url;
            }
            //判断是否是短链接
            bool Close() {
                // 没有Connection字段，或者有Connection但是值是close，则都是短链接，否则就是长连接
                if (HasHeader("Connection") == true && GetHeader("Connection") == "keep-alive") {
                    return false;
                }
                return true;
            }
    };

    typedef enum {
        RECV_HTTP_ERROR,
        RECV_HTTP_LINE,
        RECV_HTTP_HEAD,
        RECV_HTTP_BODY,
        RECV_HTTP_OVER
    }HttpRecvStatu;

    #define MAX_LINE 8192
    class HttpContext {
        private:
            int _resp_statu; //响应状态码
            HttpRecvStatu _recv_statu; //当前接收及解析的阶段状态
            HttpRequest _request;  //已经解析得到的请求信息
        private:
            bool ParseHttpLine(const std::string &line) {
                std::smatch matches;

                std::regex e(R"(^\s*(GET|HEAD|POST|PUT|DELETE)\s+([^\s?]+)(?:\?([^\s]*))?\s+(HTTP\/1\.[01])\s*$)", std::regex::icase);
                bool ret = std::regex_match(line, matches, e);
                if (ret == false) {

                    _recv_statu = RECV_HTTP_ERROR;
                    _resp_statu = 400;//BAD REQUEST
                    return false;
                }
            
                _request._method = matches[1];
                std::cout << " _request._method" << _request._method<< std::endl;
                std::transform(_request._method.begin(), _request._method.end(), _request._method.begin(), ::toupper);
                
                _request._path = Util::UrlDecode(matches[2], false);
                std::cout << " _request._path" << _request._path<< std::endl;
                
                _request._version = matches[4];
                std::cout << " _request._version" << _request._version<< std::endl;
                
                std::vector<std::string> query_string_arry;
                std::string query_string = matches[3];

                
                
                Util::Split(query_string, "&", &query_string_arry);

                for (auto &str : query_string_arry) {
                    size_t pos = str.find("=");
                    if (pos == std::string::npos) {
                        _recv_statu = RECV_HTTP_ERROR;
                        _resp_statu = 400;
                        return false;
                    }
                    std::string key = Util::UrlDecode(str.substr(0, pos), true);  
                    std::string val = Util::UrlDecode(str.substr(pos + 1), true);
                    _request.SetParam(key, val);
                }
                return true;
            }
            bool RecvHttpLine(muduo::net::Buffer*buf) {
                if (_recv_statu != RECV_HTTP_LINE) return false;

            
                std::string line = Util::getLineAndPop(buf);
                //std::cout << "RecvHttpLine: -" << line << "-"<<std::endl;

                if (line.size() == 0) {
                    
                    if (buf->readableBytes()> MAX_LINE) {
                        _recv_statu = RECV_HTTP_ERROR;
                        _resp_statu = 414;//URI TOO LONG
                        return false;
                    }
                    
                    return true;
                }
                //std::cout << "RecvHttpLine test1"<< std::endl;
                
                if (line.size() > MAX_LINE) {
                    _recv_statu = RECV_HTTP_ERROR;
                    _resp_statu = 414;//URI TOO LONG
                    return false;
                }
                //std::cout << "RecvHttpLine test2"<< std::endl;
                bool ret = ParseHttpLine(line);
                if (ret == false) {
                    return false;
                }

                //std::cout << "RecvHttpLine test3"<< std::endl;
                //首行处理完毕，进入头部获取阶段
                _recv_statu = RECV_HTTP_HEAD;
                return true;
            }

            bool RecvHttpHead(muduo::net::Buffer *buf) {
                if (_recv_statu != RECV_HTTP_HEAD) return false;
                

                while(1){
                    std::string line = Util::getLineAndPop(buf);
                   
                    if (line.size() == 0) {
                        
                        if (buf->readableBytes() > MAX_LINE) {
                            _recv_statu = RECV_HTTP_ERROR;
                            _resp_statu = 414;//URI TOO LONG
                            return false;
                        }
                        
                        return true;
                    }
                    
                    
                    //std::cout << "RecvHttpHead test1"<< std::endl;
                    if (line.size() > MAX_LINE) {
                        _recv_statu = RECV_HTTP_ERROR;
                        _resp_statu = 414;//URI TOO LONG
                        return false;
                    }
                    //std::cout << "RecvHttpHead test2"<< std::endl;
                    if (line == "\n" || line == "\r\n") {
                        std::cout << "RecvHttpHead break"<< std::endl;
                        break;
                    }
                    bool ret = ParseHttpHead(line);
                    if (ret == false) {
                        return false;
                    }
                    //std::cout << "RecvHttpHead test3"<< std::endl;
                }

                _recv_statu = RECV_HTTP_BODY;
                return true;
            }
            bool ParseHttpHead(std::string &line) {

                //std::cout << "---ParseHttpHead---"<<std::endl;
                if (line.back() == '\n') line.pop_back();
                if (line.back() == '\r') line.pop_back();
                size_t pos = line.find(": ");
                if (pos == std::string::npos) {
                    std::cout << "---ParseHttpHead---npos---error"<<std::endl;
                    _recv_statu = RECV_HTTP_ERROR;
                    _resp_statu = 400;//
                    return false;
                }
                std::string key = line.substr(0, pos);  
                std::string val = line.substr(pos + 2);
                _request.SetHeader(key, val);
                return true;
            }
            bool RecvHttpBody(muduo::net::Buffer *buf) {
                if (_recv_statu != RECV_HTTP_BODY) return false;

                //std::cout << "---RecvHttpBody---"<<std::endl;

                size_t content_length = _request.ContentLength();
                if (content_length == 0) {
            
                    _recv_statu = RECV_HTTP_OVER;
                    return true;
                }
            
                size_t real_len = content_length - _request._body.size();//实际还需要接收的正文长度
            
                if (buf->readableBytes() >= real_len) {
                    _request._body.append(buf->peek(), real_len);
                    buf->retrieve(real_len);
                    _recv_statu = RECV_HTTP_OVER;
                    return true;
                }
                
                _request._body.append(buf->peek(), buf->readableBytes());
                buf->retrieve(buf->readableBytes());
                return true;
            }
        public:
            HttpContext():_resp_statu(200), _recv_statu(RECV_HTTP_LINE) {}
            void ReSet() {
                _resp_statu = 200;
                _recv_statu = RECV_HTTP_LINE;
                _request.ReSet();
            }
            int RespStatu() { return _resp_statu; }
            HttpRecvStatu RecvStatu() { return _recv_statu; }
            HttpRequest &Request() { return _request; }

            void RecvHttpRequest(muduo::net::Buffer *buf) {
                
                switch(_recv_statu) {
                    case RECV_HTTP_LINE: RecvHttpLine(buf);
                    case RECV_HTTP_HEAD: RecvHttpHead(buf);
                    case RECV_HTTP_BODY: RecvHttpBody(buf);
                }
                return;
            }
    };




    class HttpServer {
    private:
        using Handler = std::function<void(const HttpRequest&, HttpResponse*)>;
        using Handlers = std::vector<std::pair<std::regex, Handler>>;
        
        Handlers get_route_;
        Handlers post_route_;
        Handlers put_route_;
        Handlers delete_route_;
        std::string basedir_;
        
        muduo::net::EventLoop loop_;
        muduo::net::TcpServer server_;

    public:
        HttpServer(int port, const std::string& name, int timeout = 30)
            : server_(&loop_, muduo::net::InetAddress(port), name) {
            
            server_.setConnectionCallback(
                std::bind(&HttpServer::OnConnected, this, std::placeholders::_1));
            server_.setMessageCallback(
                std::bind(&HttpServer::OnMessage, this, std::placeholders::_1, 
                        std::placeholders::_2, std::placeholders::_3));
        }

    private:
        void ErrorHandler(const HttpRequest& req, HttpResponse* rsp) {
            std::string body;
            body += "<html>";
            body += "<head>";
            body += "<meta http-equiv='Content-Type' content='text/html;charset=utf-8'>";
            body += "</head>";
            body += "<body>";
            body += "<h1>";
            body += std::to_string(rsp->_statu);
            body += " ";
            body += Util::StatuDesc(rsp->_statu);
            body += "</h1>";
            body += "</body>";
            body += "</html>";
        
            rsp->SetContent(body, "text/html");
        }

        void WriteResponse(const muduo::net::TcpConnectionPtr& conn, 
                        const HttpRequest& req, HttpResponse& rsp) {
            if (req.Close()) {
                rsp.SetHeader("Connection", "close");
            } else {
                rsp.SetHeader("Connection", "keep-alive");
            }
            
            if (!rsp._body.empty() && !rsp.HasHeader("Content-Length")) {
                rsp.SetHeader("Content-Length", std::to_string(rsp._body.size()));
            }
            
            if (!rsp._body.empty() && !rsp.HasHeader("Content-Type")) {
                rsp.SetHeader("Content-Type", "application/octet-stream");
            }
            
            if (rsp._redirect_flag) {
                rsp.SetHeader("Location", rsp._redirect_url);
            }

            std::stringstream rsp_str;
            rsp_str << req._version << " " << std::to_string(rsp._statu) << " " 
                    << Util::StatuDesc(rsp._statu) << "\r\n";
            
            for (auto& head : rsp._headers) {
                rsp_str << head.first << ": " << head.second << "\r\n";
            }
            
            rsp_str << "\r\n";
            rsp_str << rsp._body;

            conn->send(rsp_str.str());
        }

        bool IsFileHandler(const HttpRequest& req) {
            if (basedir_.empty()) return false;
            if (req._method != "GET" && req._method != "HEAD") return false;
            if (!Util::ValidPath(req._path)) return false;
            
            std::string req_path = basedir_ + req._path;
            if (req._path.back() == '/') {
                req_path += "index.html";
            }
            
            return Util::IsRegular(req_path);
        }

        void FileHandler(const HttpRequest& req, HttpResponse* rsp) {
            std::string req_path = basedir_ + req._path;
            if (req._path.back() == '/') {
                req_path += "index.html";
            }
            
            if (Util::ReadFile(req_path, &rsp->_body)) {
                rsp->SetHeader("Content-Type", Util::ExtMime(req_path));
            }
        }

        void Dispatcher(HttpRequest& req, HttpResponse* rsp, Handlers& handlers) {
            for (auto& handler : handlers) {
                const std::regex& re = handler.first;
                const Handler& functor = handler.second;
                
                if (std::regex_match(req._path, req._matches, re)) {
                    return functor(req, rsp);
                }
            }
            rsp->_statu = 404;
        }

        void Route(HttpRequest& req, HttpResponse* rsp) {
            if (IsFileHandler(req)) {
                return FileHandler(req, rsp);
            }
            
            if (req._method == "GET" || req._method == "HEAD") {
                return Dispatcher(req, rsp, get_route_);
            } else if (req._method == "POST") {
                return Dispatcher(req, rsp, post_route_);
            } else if (req._method == "PUT") {
                return Dispatcher(req, rsp, put_route_);
            } else if (req._method == "DELETE") {
                return Dispatcher(req, rsp, delete_route_);
            }
            
            rsp->_statu = 405; // Method Not Allowed
        }

        void OnConnected(const muduo::net::TcpConnectionPtr& conn) {
            if (conn->connected()) {
                // 初始化连接上下文
                conn->setContext(HttpContext());
                LOG_INFO << "New connection: " << conn->name();
            } else {
                LOG_INFO << "Connection closed: " << conn->name();
            }
        }

        void OnMessage(const muduo::net::TcpConnectionPtr& conn, 
                    muduo::net::Buffer* buffer, 
                    muduo::Timestamp) {


            std::cout << "=== Raw Request ===" << std::endl;
            std::cout << std::string(buffer->peek(), buffer->readableBytes()) << std::endl;
            std::cout << "===================" << std::endl;
            
            while (buffer->readableBytes() > 0) {
                HttpContext* context = boost::any_cast<HttpContext>(conn->getMutableContext());
                
                std::cout << "context->RecvHttpRequest" << std::endl;
                context->RecvHttpRequest(buffer);
                HttpRequest& req = context->Request();
                HttpResponse rsp(context->RespStatu());
                
                std::cout << "context->RespStatu()" << context->RespStatu() <<std::endl;

                if (context->RespStatu() >= 400) {
                    ErrorHandler(req, &rsp);
                    WriteResponse(conn, req, rsp);
                    context->ReSet();
                    buffer->retrieveAll(); 
                    conn->shutdown();
                    return;
                }
                
                if (context->RecvStatu() != RECV_HTTP_OVER) {
                    return;
                }
                
                Route(req, &rsp);
                WriteResponse(conn, req, rsp);
                context->ReSet();
                
                if (rsp.Close()) {
                    conn->shutdown();
                }
            }
        }

    public:
        void SetBaseDir(const std::string& path) {
            assert(Util::IsDirectory(path));
            basedir_ = path;
        }
        
        void Get(const std::string& pattern, const Handler& handler) {
            get_route_.emplace_back(std::regex(pattern), handler);
        }
        
        void Post(const std::string& pattern, const Handler& handler) {
            post_route_.emplace_back(std::regex(pattern), handler);
        }
        
        void Put(const std::string& pattern, const Handler& handler) {
            put_route_.emplace_back(std::regex(pattern), handler);
        }
        
        void Delete(const std::string& pattern, const Handler& handler) {
            delete_route_.emplace_back(std::regex(pattern), handler);
        }
        
        void SetThreadCount(int count) {
            server_.setThreadNum(count);
        }
        
        void Listen() {
            server_.start();
            loop_.loop();
        }
    };
}